package com.rem.flink.flink3Transform;


import com.rem.flink.flink2Source.ClickSource;
import com.rem.flink.flink2Source.Event;
import org.apache.flink.api.common.functions.Partitioner;
import org.apache.flink.api.java.functions.KeySelector;
import org.apache.flink.streaming.api.datastream.DataStreamSink;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.source.RichParallelSourceFunction;

/**
 * 物理分区  将数据重新分布传递到不同的流分区去进行下一步处理 （物理分区）
 * keyBy就是按照键的哈希值来进行分区操作 （软分区）
 *
 * @author Rem
 * @date 2022/10/9
 */
public class TransformPhysicalPartitioningTest {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);

        //有了自定义的source function，调用addSource方法
        DataStreamSource<Event> stream = env.addSource(new ClickSource());

        // 1. 随机分区 均匀分布带下游算子
        //shuffle(stream);

        // 2. 轮询分区 依次分发
        //rebalance(stream);

        // 3. 重缩放分区 与轮询分区类似 只是"发牌人"面向特定份群体发牌    轮询分区是"发牌人"会面向所有人发牌
        //rescale(env);

        // 4. 广播  数据会在不同的分区都保留一份，可能进行重复处理
        //broadcast(stream);

        // 5. 全局分区 将所有的输入流都发送到下游算子的第一个并行任务中去，强行让下藕任务并行度为1
        //global(stream);

        // 6. 自定义重分区 将自然数按照奇偶分区
        env.fromElements(1, 2, 3, 4, 5, 6, 7, 8)
                .partitionCustom(new Partitioner<Integer>() {
                    @Override
                    public int partition(Integer key, int numPartitions) {
                        return key % 2;
                    }
                }, (KeySelector<Integer, Integer>) value -> value)
                .print().setParallelism(2);

        env.execute();
    }

    private static DataStreamSink<Event> global(DataStreamSource<Event> stream) {
        return stream.global().print("global").setParallelism(4);
    }

    private static void broadcast(DataStreamSource<Event> stream) {
        stream.broadcast().print("broadcast").setParallelism(4);
    }

    private static void rescale(StreamExecutionEnvironment env) {
        env.addSource(new RichParallelSourceFunction<String>() {  // 这里使用了并行数据源的富函数版本
                    @Override
                    public void run(SourceContext<String> sourceContext) {
                        for (int i = 1; i <= 8; i++) {
                            // 将奇数发送到索引为1的并行子任务
                            // 将偶数发送到索引为0的并行子任务
                            if (i % 2 == getRuntimeContext().getIndexOfThisSubtask()) {
                                sourceContext.collect("num:" + i);
                            }
                        }
                    }

                    @Override
                    public void cancel() {

                    }
                })
                .setParallelism(2)
                .rescale()
                .print()
                .setParallelism(4);
    }

    private static void rebalance(DataStreamSource<Event> stream) {
        stream.rebalance().print("rebalance").setParallelism(4);
    }

    private static void shuffle(DataStreamSource<Event> stream) {
        stream.shuffle().print("shuffle").setParallelism(4);
    }

}

